home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir39 / cmos16.zip / CMOS.ASM < prev    next >
Assembly Source File  |  1994-08-28  |  16KB  |  675 lines

  1.     PAGE    60,132
  2. NAME    CMOSSAVE
  3.     TITLE    CMOSSave Save CMOS to a file on disk or floppy
  4. Comment |
  5.     Version 1.6 1994 Augest 29 Roedy Green
  6.     works with MASM 6.0 and Optasm
  7.     This assembler code generates all three programs:
  8.     CMOSSAVE.COM CMOSREST.COM and CMOSCHK.COM.
  9.  
  10. See CMOS.TXT for details on use.
  11.  
  12.   USAGE:
  13.  
  14. Examples:
  15. *********
  16.  
  17. CMOSSave A:\MyCMOS.Sav
  18.  
  19. CMOSRest A:\MyCMOS.Sav
  20.  
  21. CMOSChk  A:\ByCMOS.Sav
  22.  
  23. Syntax errors or missing file trouble generates an ERRORLEVEL 4.
  24. CMOSChk generates an ERRORLEVEL 1 if the CMOS has changed since
  25. the CMOSSave was done.
  26.  
  27. Version History
  28. ***************
  29.  
  30. Version 1.0
  31. - released to BIX 91/09/07
  32.  
  33. Version 1.1
  34. - released to BIX 91/09/18
  35. - added special check for small 64 character CMOSes.
  36.  
  37. Version 1.2
  38. - fix spelling errors
  39. - use CMOS.SAV instead of MyCMOS.SAV in examples
  40.  
  41. Version 1.3
  42. - now consider fewer bytes volatile, restore more stuff.
  43. - hints in docs about clearing CMOS.
  44.  
  45. Version 1.4
  46. - now consider flags Status register C, offset 0C as volatile.
  47.   fixes false alarms.
  48.  
  49. Version 1.5 1994 June 1
  50. - change of address and phone number
  51. - address now appears in the banner.
  52.  
  53. Version 1.6 1994 August 29
  54. - more information about how CMOS bits are used.
  55.  
  56. CMOS Usage - see also CMOS.OFS
  57.  
  58. How to Assemble
  59. ***************
  60.  
  61. Manually set the GENERATING equate embedded in this code, then:
  62.  
  63. to assemble with MASM 6.0 use:
  64. ML.EXE /AT /c /Fl /VM /Zf /Zm CMOS.Asm
  65. LINK.EXE /TINY /MAP CMOS.Obj,CMOS.com,CMOS.map;
  66. copy cmos.com cmossave.com
  67.  
  68. to assemble with OPTASM use:
  69. Optasm     CMOS.Asm,CMOS.Obj,CMOS.Lst/L/N/G/S
  70. OLINK     CMOS.Obj,CMOS.COM,/MAP/TINY;
  71. copy cmos.com cmossave.com
  72.  
  73. Register Conventions
  74. ********************
  75.  
  76. Subroutines may trash all registers except those explicity
  77. documented as input or output.
  78.  
  79. | ; end of comment
  80.  
  81.  
  82. ;    E Q U A T E S
  83.  
  84. CMOSSAVE    EQU    1
  85. CMOSREST    EQU    2
  86. CMOSCHK     EQU    3
  87.  
  88. ; use /DGenerating#CMOSSAVE
  89. ;     /DGenerating#CMOSREST
  90. ;     /DGenerating#CMOSCHK
  91. ; on the assembler command line to select which version
  92. ; of the code to assemble.
  93. ;    Or add code following of the form:
  94.  
  95. ; GENERATING EQU CMOSSave
  96.  
  97.  
  98.     If    Generating eq CMOSSave
  99. %OUT Generating CMOSSave.Com
  100.     Endif
  101.  
  102.     If    Generating eq CMOSRest
  103. %OUT Generating CMOSRest.Com
  104.     endif
  105.  
  106.     If    Generating eq CMOSChk
  107. %OUT Generating CMOSChk.Com
  108.     endif
  109. ;==============================================================
  110.  
  111.  
  112. stack    segment stack        ; keep MS link happy by providing null stack
  113. stack    ends
  114.  
  115. CODE    SEGMENT PARA        ; start off in code.
  116.  
  117. ;==============================================================
  118.  
  119. data    segment byte        ; provide a separate DATA segment
  120.                 ; actually all come after the code
  121. ;==============================================================
  122. ;  V A R I A B L E S
  123.  
  124.  
  125.     If    Generating eq CMOSSave
  126.  
  127. BannerMsg    DB '░▒▓█ CMOSSave 1.6 █▓▒░',13d,10d
  128.         DB 13d,10d
  129.         DB 'Saves contents of CMOS to a file on hard disk or floppy.',13,10
  130.         DB 'Copyright (c) 1991,1994 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  131.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  132.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  133.         DB 13,10
  134.         db '$'
  135.  
  136. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  137.         DB 'Insert a formatted diskette.',13,10
  138.         DB 'then try:',13,10
  139.         DB 'CMOSSave A:\CMOS.Sav',13,10
  140.         DB 'or if want to save on hard disk try:',13,10
  141.         DB 'CMOSSave C:\CMOS.Sav',13,10
  142.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  143.         db '$'
  144.  
  145. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  146.         DB 'Cannot create the disk file.',13,10
  147.         db '$'
  148.  
  149. WorkedMsg    DB 'CMOS successfully saved',13,10
  150.         db '$'
  151.  
  152.     EndIf
  153.  
  154.  
  155.     If    Generating eq CMOSRest
  156. BannerMsg    DB '░▒▓█ CMOSRest 1.6 █▓▒░',13d,10d
  157.         DB 13d,10d
  158.         DB 'Restores CMOS from a CMOSSave file on hard disk or floppy.',13,10
  159.         DB 'Copyright (c) 1991,1994 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  160.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  161.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  162.         DB 13,10
  163.         db '$'
  164.  
  165. UsageMsg    DB '░▒▓█ Error █▓▒░',13,10
  166.         DB 'Insert the diskette you used for CMOSSave.',13,10
  167.         DB 'then try:',13,10
  168.         DB 'CMOSRest A:\CMOS.Sav',13,10
  169.         DB 'or if the file is on hard disk try:',13,10
  170.         DB 'CMOSRest C:\CMOS.Sav',13,10
  171.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  172.         db '$'
  173.  
  174. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  175.         DB 'Cannot find/read the disk file.',13,10
  176.         db '$'
  177.  
  178. WorkedMsg    DB 'CMOS successfully restored',13,10
  179.         db '$'
  180.  
  181.     EndIf
  182.  
  183.     If    Generating eq CMOSChk
  184. BannerMsg    DB '░▒▓█ CMOSChk 1.6 █▓▒░',13d,10d
  185.         DB 13d,10d
  186.         DB 'Ensures CMOS not corrupted or changed.',13,10
  187.         DB 'Copyright (c) 1991,1994 Roedy Green Canadian Mind Products (604) 685-8412.',13,10
  188.         DB '#601 - 1330 Burrard, Vancouver BC CANADA  V6Z 2B8',13,10
  189.         DB 'Shareware to freely distribute and use for any purpose except military.',13,10
  190.         DB 13,10
  191.         db '$'
  192.  
  193. UsageMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  194.         DB 'Insert the diskette you used for CMOSSave.',13,10
  195.         DB 'then try:',13,10
  196.         DB 'CMOSChk A:\CMOS.Sav',13,10
  197.         DB 'or if you have the file on hard disk try:',13,10
  198.         DB 'CMOSChk C:\CMOS.Sav',13,10
  199.         DB 'Read CMOS.TXT to find how to use it properly.',13,10
  200.         db '$'
  201.  
  202. FileTroubleMsg    DB '░▒▓█ Error █▓▒░',7,13,10
  203.         DB 'Cannot find/read the disk file.',13,10
  204.         db '$'
  205.  
  206. MatchTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
  207.         DB 'CMOS has been corrupted!',13,10
  208.         db '$'
  209.  
  210. WorkedMsg    DB 'CMOS is OK, i.e. unchanged since the last CMOSSave.',13,10
  211.         db '$'
  212.  
  213.     EndIf
  214.  
  215.  
  216. FilenamePtr    DW    0
  217.             ; pointer to filename in command line
  218.  
  219. CMOSSize    DB    0
  220.             ; size of cmos in bytes
  221.  
  222. CMOSBuff    db 0    ; dynamic buffer will grow to 128
  223.             ; it hangs out past the end of the program
  224.  
  225. data        ends
  226.  
  227. com    group    code,data    ; force data segment to go at the end
  228.  
  229.     ASSUME    CS:com,DS:com,ES:com,SS:com
  230.                 ; seg regs cover everything
  231.     ORG    100H        ; in Code segment
  232.  
  233. ;==========================
  234.  
  235. Main    proc    far
  236.  
  237. ;    M A I N L I N E   R O U T I N E
  238. Start:
  239.     lea    dx,BannerMsg    ; display the banner
  240.     Call    Say
  241.     Call    Parse        ; get filename from command line
  242.  
  243.     If    Generating eq CMOSSave
  244.     call    GetCMOS     ; fetch CMOS to buffer
  245.     call    WriteCMOS    ; write CMOS contents to file
  246.     EndIf
  247.  
  248.     If    Generating eq CMOSRest
  249.     call    ReadCMOS    ; read CMOS contents from file
  250.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  251.     call    PutCMOS     ; store buffer to CMOS
  252.     EndIf
  253.  
  254.     If    Generating eq CMOSChk
  255.     call    ReadCMOS    ; read CMOS contents from file
  256.     call    CalcCMOSSize    ; it is 64 or 128 bytes long?
  257.     call    CompareCMOS    ; compare CMOS with buffer
  258.     EndIf
  259.  
  260.     lea    dx,WorkedMsg    ; crow about success
  261.     Call    Say
  262. Done:
  263.     mov    ax,4c00h
  264.     int    21h        ;normal termination
  265.  
  266. Main    EndP
  267.  
  268. ;===============================================================
  269.  
  270. Trouble proc    near
  271.  
  272. FileTrouble:
  273.     Lea    dx,FileTroubleMsg    ; display file trouble
  274.     Call    Say
  275.     Jmp    Abort
  276.  
  277. abort:
  278.                 ; error exit
  279.     mov    ax, 4c04h    ; ERRORLEVEL = 4
  280.     int    21h        ; DIE
  281.  
  282. Trouble endp
  283.  
  284. ;===============================================================
  285.  
  286. MLeading    PROC    Near
  287.  
  288. ;    Remove leading blanks
  289. ;    on entry BX is addr of string, CX its length
  290. ;    trims off any leading blanks, leaving result in BX CX
  291. ;    length may also be 0 or 1, but not -ve
  292. ;    If the entire string is blank the result is the null string
  293.     mov    di,bx
  294.     mov    al,20H        ; AL = blank  -- the search char
  295.     jcxz    mleading2    ; jump if null string
  296.     repe    scasb        ; scan ES:DI forwards till hit non blank
  297.                 ; DI points just after it (wrap ok)
  298.                 ; cx IS ONE TOO SMALL, OR 0 IF NONE FOUND
  299.     je    mleading1    ; jump if entire string was blank
  300.     inc    cx        ; CX is length of remainder of string
  301. mleading1:
  302.     dec    di        ; DI points to non-blank
  303. mleading2:
  304.     mov    bx,di        ; put address back
  305.     ret
  306.  
  307. MLeading    ENDP
  308.  
  309. ;========================================
  310.  
  311. MTrailing    PROC    Near
  312.  
  313. ;    Remove trailing blanks.
  314. ;    on entry BX is addr of string, CX its length
  315. ;    trims off any trailing blanks, leaving result in BX CX
  316. ;    length may also be 0 or 1, but not -ve
  317. ;    If the entire string is blank the result is the null string
  318.     mov    di,bx
  319.     add    di,cx        ; calc addr last char in string
  320.     dec    di
  321.     mov    al,20H        ; AL = blank  -- the search char
  322.     jcxz    mtrailing1    ; jump if null string
  323.     std
  324.     repe    scasb        ; scan ES:DI backwards till hit non blank
  325.                 ; DI points just ahead of it (wrap ok)
  326.                 ; CX is one too small, or 0 if none found
  327.     cld
  328.     je    mtrailing1    ; jump if whole string was blank
  329.     inc    cx
  330. mtrailing1:
  331.     ret
  332.  
  333. MTrailing    ENDP
  334.  
  335. ;========================================
  336.  
  337. Parse        PROC    NEAR
  338. ;    Parse the command line to remove lead/trail blanks from
  339. ;    the single drive parameter and terminate it by 2 nulls.
  340. ;    sample inputs
  341. ;    CMOSRest A:\CMOS.SAV
  342. ;    CMOSRest    B:\MySub\MyCMOS.SAV
  343. ;
  344. ;    When Done DS:BX points to start of string.
  345. ;    String will be terminated by 2 nulls
  346. ;    CX counts bytes in string exclusive of nulls
  347.                 ; counted string at HEX 80 PSP
  348.                 ; contains command line.
  349.                 ; Preceeded by unwanted spaces.
  350.                 ; possibly followed by unwanted spaces.
  351.                 ; currently missing a trailing null.
  352.     xor    ch,ch
  353.     mov    cl,ds:80H
  354.     mov    bx,81H
  355.     call    Mleading    ; get rid of leading blanks
  356.     call    MTrailing    ; get rid of trailing blanks
  357.     mov    di,bx        ; calc addr of byte just past end
  358.     add    di,cx
  359.     mov    word ptr [di],0 ; plop in pair of nulls after string
  360.     mov    FileNamePtr,bx    ; remember where filename was
  361.     jcxz    SyntaxTrouble    ; missing parm.
  362.     ret
  363.  
  364. SyntaxTrouble:
  365.     lea    dx,UsageMsg        ; display usage message
  366.     Call    Say
  367.     Jmp    Abort
  368.  
  369. Parse        ENDP
  370.  
  371. ;======================================
  372.  
  373. Say    Proc
  374.  
  375. ;    on entry DX points to a string to display
  376.  
  377.     MOV    AH,9
  378.     Int    21h
  379.     ret
  380.  
  381. Say    EndP
  382.  
  383. ;======================================
  384.  
  385.     If    Generating eq CMOSSave
  386.  
  387. GetCMOS Proc    Near
  388.  
  389. ;    Get 128 byte contents of CMOS into a buffer.
  390.  
  391.     mov    cx,128        ; count of times through loop
  392.     lea    bx,CMOSBuff    ; where to put the contents
  393.     sub    al,al        ; start offset in CMOS
  394. GetLoop:
  395.     Call    PeekCmos    ; al=offset ah=contents
  396.     mov    byte ptr[bx],ah
  397.     inc    al
  398.     inc    bx
  399.     loop    GetLoop
  400.     ret
  401.  
  402. GetCMOS EndP
  403.  
  404.     EndIf
  405.  
  406. ;===============================================================
  407.  
  408.     If    Generating eq CMOSRest
  409.  
  410. PutCMOS Proc    Near
  411.  
  412. ;    Put 128-byte contents of buffer into CMOS.
  413. ;    do not touch the volatile bytes
  414.  
  415.     mov    cx,128        ; count of times through loop
  416.     lea    bx,CMOSBuff    ; where to put the contents
  417.     sub    al,al        ; start offset in CMOS
  418. PutLoop:
  419.     call    Volatile    ; test if this is a volatile byte
  420.                 ; test offset in al
  421.     jc    LeaveItAlone
  422.     mov    ah,byte ptr[bx]
  423.     Call    PokeCMOS    ; al=offset ah=contents
  424.  
  425. LeaveItAlone:
  426.     inc    bx
  427.     inc    al
  428.     loop    PutLoop
  429.     ret
  430.  
  431. PutCMOS EndP
  432.  
  433.     EndIf
  434.  
  435. ;===============================================================
  436.  
  437.     If    Generating eq CMOSChk
  438.  
  439. CompareCMOS    proc    Near
  440.  
  441. ;    compares buffer version of CMOS with contents of actual CMOS
  442. ;    ignores mismatches of volatile bytes.
  443. ;    Aborts if finds a mismatch
  444.  
  445.     mov    cx,128        ; count of times through loop
  446.     lea    bx,CMOSBuff    ; where to find comparison set
  447.     sub    al,al        ; start offset in CMOS
  448. CompLoop:
  449.     call    Volatile    ; test if this is a volatile byte
  450.                 ; test offset in al
  451.     jc    IgnoreMismatch
  452.     Call    PeekCMOS    ; al=offset ah=contents
  453.     cmp    ah,byte ptr[bx] ; compare CMOS with buffer
  454.     jne    MatchTrouble
  455.  
  456. IgnoreMismatch:
  457.     inc    bx
  458.     inc    al
  459.     loop    CompLoop
  460.     ret
  461.  
  462. MatchTrouble:
  463.     lea    dx,MatchTroubleMsg    ; display CMOS mismatch
  464.     call    Say
  465.     mov    ax, 4c01h        ; ERRORLEVEL = 1
  466.     int    21h            ; DIE
  467.  
  468. CompareCMOS    EndP
  469.  
  470.     EndIf
  471.  
  472. ;===============================================================
  473.  
  474.     If    Generating ne CMOSSave
  475.  
  476. Volatile    Proc    near
  477.  
  478. ;    Is cmos offset in AL volatile?    If so set carry.
  479. ;    These bytes will be undisturbed.
  480. ;    Preserves all registers.
  481. ;    00..09, 0C and 32 are volatile, rest are not.
  482. ;    0A 0B 0D 0E 0F used to be considered volatile, now are not.
  483. ;    if cmos is small, all bytes past end are considered volatile
  484.  
  485.     cmp    al,CMOSSize        ; bytes past end are volatile
  486.     jae    IsVolatile
  487.     cmp    al,09h
  488.     jbe    IsVolatile        ; early bytes are for timing
  489.     cmp    al,0Ch            ; flags status register
  490.     je    IsVolatile        ; is considered volatile
  491.     cmp    al,32h            ; 32 is date century byte,
  492.     je    IsVolatile        ; not exactly volatile, but ...
  493.  
  494. IsNotVolatile:
  495.     clc                ; clear carry
  496.     ret
  497.  
  498. IsVolatile:
  499.     stc
  500.     ret
  501.  
  502. Volatile    EndP
  503.     EndIf
  504.  
  505. ;===============================================================
  506.  
  507.     If    Generating ne CMOSSave
  508.  
  509. CalcCMOSSize    Proc    near
  510.  
  511. ;    Is CMOS 64 or 128 bytes long?
  512. ;    It is 64 if bytes at 10..2F match those at 50..6F.
  513. ;    Otherwise it is 128 bytes.
  514. ;    Preserves all registers.
  515.  
  516.     push    si
  517.     push    di
  518.     push    cx
  519.     lea    si,CMOSBuff+10h
  520.     lea    di,CMOSBuff+50h
  521.     mov    cx,02fh+1-10h
  522.     repe    cmpsb
  523.     je    IsCMOS64
  524.  
  525. IsCMOS128:
  526.     mov    CMOSSize,128    ; differ, must be a big CMOS
  527.     jmp    CalcCMOSSizeDone
  528.  
  529. IsCMOS64:
  530.     mov    CMOSSize,64    ; all same, small CMOS
  531.  
  532. CalcCMOSSizeDone:
  533.     pop    cx
  534.     pop    di
  535.     pop    si
  536.  
  537.     ret
  538.  
  539. CalcCMOSSize    EndP
  540.     EndIf
  541.  
  542. ;===============================================================
  543.  
  544.     if    Generating ne CMOSRest
  545.  
  546. PeekCMOS    proc    near
  547.  
  548. ;    Reads one byte from cmos.
  549. ;    on entry al has offset desired
  550. ;    on exit ah has the contents of that byte.
  551. ;    preserves all registers
  552.  
  553. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to read CMOS
  554. ;    We always enable the NMI with bit 7 on.
  555.  
  556.     push    bx
  557.     push    ax
  558.     cli                ; disable interrupts
  559.     or    al,80h            ; disable NMI
  560.     out    70h,al            ; output the byte address to CMOS
  561.     jmp    $+2            ; delay, safer than nop
  562.     in    al,71h            ; read the CMOS byte
  563.     jmp    $+2            ; delay, safer than nop
  564.     mov    bl,al
  565.                     ; re-enable the NMI
  566.     mov    al,0dh            ; point to battery status register
  567.     out    70h,al            ; leave pointing at a safe r/o register
  568.     sti                ; restore interrupts
  569.     pop    ax
  570.     mov    ah,bl
  571.     pop    bx
  572.     ret
  573.  
  574. PeekCMOS    EndP
  575.  
  576.     EndIf
  577.  
  578. ;===============================================================
  579.  
  580.     If    Generating eq CMOSRest
  581.  
  582. PokeCMOS    proc    near
  583.  
  584. ;    Stuffs one byte into cmos.
  585. ;    on entry al has offset desired, ah has the value to stuff.
  586. ;    Preserves all registers.
  587.  
  588. ;    See page 5-81 IBM AT Tech ref BIOS listing for how to write CMOS
  589. ;    We always enable the NMI with bit 7 on.
  590.  
  591.     push    ax
  592.     cli                ; disable interrupts
  593.     or    al,80h            ; disable NMI
  594.     out    70h,al            ; output the byte address to CMOS
  595.     jmp    $+2            ; delay, safer than nop
  596.  
  597.     mov    al,ah            ; get contents
  598.     out    71h,al            ; poke the CMOS byte
  599.     jmp    $+2            ; delay, safer than nop
  600.                     ; re-enable the NMI
  601.     mov    al,0dh            ; point to battery status register
  602.     out    70h,al            ; leave pointing at a safe r/o register
  603.     sti                ; restore interrupts
  604.     pop    ax
  605.     ret
  606.  
  607. PokeCMOS    EndP
  608.  
  609.     EndIf
  610.  
  611. ;===============================================================
  612.  
  613.     If    Generating ne CMOSSave
  614.  
  615. ReadCMOS    Proc    Near
  616.  
  617. ;    Open a file read the CMOS into a buffer
  618.  
  619.     mov    dx,FileNamePtr    ; DS:DX point to file
  620.     xor    al,al        ; AL=0 is attribute read/only
  621.     mov    ah,03Dh     ; DOS open function
  622.     int    21h
  623.     jc    FileTrouble
  624.     mov    bx,ax        ; save handle
  625.     mov    cx,128        ; read 128 bytes
  626.     lea    dx,CMOSBuff    ; buffer address
  627.     mov    ah,3fH        ; DOS read
  628.     int    21h
  629.     jc    FileTrouble
  630.     cmp    ax,128
  631.     jne    FileTrouble
  632.     mov    ah,3eh        ; DOS close
  633.     int    21h
  634.     jc    FileTrouble
  635.     ret
  636.  
  637. ReadCMOS    EndP
  638.  
  639.     EndIf
  640.  
  641. ;===============================================================
  642.  
  643.     if    Generating eq CMOSSave
  644.  
  645. WriteCMOS    Proc    Near
  646.  
  647. ;    Create a file write CMOS to it
  648.  
  649.     mov    dx,FileNamePtr    ; DS:DX point to file
  650.     xor    cx,cx        ; CX=0 is attribute
  651.     mov    ah,03ch     ; DOS create function
  652.     int    21h
  653.     jc    FileTrouble
  654.     mov    bx,ax        ; SAVE HANDLE
  655.     MOV    CX,128        ; write 128 bytes
  656.     lea    dx,CMOSBuff    ; buffer address
  657.     mov    ah,40h        ; DOS write
  658.     int    21h
  659.     jc    FileTrouble
  660.     cmp    ax,128
  661.     jne    FileTrouble
  662.     mov    ah,3eh        ; DOS close
  663.     int    21h
  664.     jc    FileTrouble
  665.     ret
  666.  
  667. WriteCMOS    EndP
  668.  
  669.     EndIf
  670.  
  671. ;===============================================================
  672.  
  673. CODE    ends            ; end of code segment
  674.     end    Start
  675.